#pragma once
#include <iostream>
#include <vector>
#include <semaphore.h>
#include <pthread.h>
template <typename T>
class RingQueue
{
private:
    void P(sem_t &sem)
    {
        sem_wait(&sem);
    }
    void V(sem_t &sem)
    {
        sem_post(&sem);
    }

    void Lock(pthread_mutex_t& mutex)
    {
        pthread_mutex_lock(&mutex);
    }
     void UnLock(pthread_mutex_t& mutex)
    {
        pthread_mutex_unlock(&mutex);
    }
public:
    RingQueue(int cap) : _ring_queue(cap), _cap(cap), _productor_step(0), _consumer_step(0)
    {

        sem_init(&_sem_room, 0, cap);
        sem_init(&_sem_data, 0, 0);
        pthread_mutex_init(&_productor_mutex,nullptr);
        pthread_mutex_init(&_consumer_mutex,nullptr);
    }
    void Enqueue(T in)
    {
        P(_sem_room);//有空间抢占，没空间等待
        Lock(_productor_mutex);//预定到空间后再竞争锁
        _ring_queue[_productor_step++] = in;
        _productor_step %= _cap;
        UnLock(_productor_mutex);
        V(_sem_data);//数据++
    }
    void Pop(T *out)
    {
        P(_sem_data);//有资源抢占，没资源等待
        Lock(_consumer_mutex);//上锁
        *out = _ring_queue[_consumer_step++];
        _consumer_step %= _cap;
        UnLock(_consumer_mutex);
        V(_sem_room);
    }
    ~RingQueue()
    {
        sem_destroy(&_sem_data);
        sem_destroy(&_sem_room);
        pthread_mutex_destroy(&_productor_mutex);
        pthread_mutex_destroy(&_consumer_mutex);
    }

private:
    int _cap;                   // 环形队列的容量
    std::vector<T> _ring_queue; // 环形队列

    int _productor_step; // 生产者下标
    int _consumer_step;  // 消费者下标

    sem_t _sem_data; // 数据信号量，消费者关心的
    sem_t _sem_room; // 空间信号量，生产者关心的

    pthread_mutex_t _productor_mutex;//生产者的锁，维护生产者互斥
    pthread_mutex_t _consumer_mutex;//消费者的锁，维护消费者互斥
};